﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using EPiServer.Core;

namespace EPiBoost.Core.DataAnnotations.Validators
{
	[AttributeUsage(AttributeTargets.Property)]
	public class AvailableContentTypesAttribute : ValidationAttribute
	{
		public Type[] Include { get; set; }
		public Type[] Exclude { get; set; }

		public override bool IsValid(object value)
		{
			if(!(value is ContentArea))
			{
				throw new ValidationException("AvailableContentTypesAttribute is intended only for use with ContentArea properties");
			}

			var contentArea = value as ContentArea;

			var notAllowedcontentNames = new List<string>();

			if (contentArea != null)
			{
				if (Include != null)
				{
					var notAllowedContent = contentArea.Contents.Where(x => !ContainsType(Include, x.GetType()));
					if (notAllowedContent.Any())
					{
						notAllowedcontentNames.AddRange(notAllowedContent.Select(x=>string.Format("{0} ({1})", x.Name, x.ContentLink.ID)));
					}
				}
				if (Exclude != null)
				{
					var notAllowedContent = contentArea.Contents.Where(x => ContainsType(Exclude, x.GetType()));
					if (notAllowedContent.Any())
					{
						notAllowedcontentNames.AddRange(notAllowedContent.Select(x => string.Format("{0} ({1})", x.Name, x.ContentLink.ID)));
					}
				}
			}

			if(notAllowedcontentNames.Any())
			{
				ErrorMessage = "contains invalid content items :";
				foreach (var notAllowedcontentName in notAllowedcontentNames)
				{
					ErrorMessage += " " + notAllowedcontentName + ",";
				}
				ErrorMessage = ErrorMessage.TrimEnd(',');

				return false;
			}
			return true;
		} 

		private bool ContainsType(Type[] include, Type type)
		{
			return include.Any(inc => inc.IsAssignableFrom(type));
		}

		protected override ValidationResult IsValid(object value, ValidationContext validationContext)
		{ 
			var result =  base.IsValid(value, validationContext);
			if(result!=null && !string.IsNullOrEmpty(result.ErrorMessage))
			{
				result.ErrorMessage =  string.Format("{0} {1}", validationContext.DisplayName, ErrorMessage);
			}
			return result;
		}
	}
}
